package com.homestead.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.homestead.bo.CreateUserBo;
import com.homestead.config.OAuth2ClientConfiguration;
import com.homestead.constant.Constant;
import com.homestead.constant.UrlConstant;
import com.homestead.controller.vo.LoginUserInfoVo;
import com.homestead.domain.OAuthUserInfo;
import com.homestead.domain.entity.BackUser;
import com.homestead.domain.mapper.BackUserMapper;
import com.homestead.exception.UserException;
import com.homestead.resp.CommonResponse;
import com.homestead.service.UserService;
import com.homestead.utils.RSAUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.Objects;


@Service
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class UserServiceImpl extends ServiceImpl<BackUserMapper, BackUser> implements UserService {
    private final OAuth2ClientConfiguration oAuth2ClientConfiguration;
    private final RestTemplate restTemplate;

    @Override
    public boolean create(CreateUserBo bo) throws Exception {
        BackUser backUser = new BackUser();
        long id = IdUtil.createSnowflake(Constant.WORKER_ID, Constant.DATA_CENTER_ID).nextId();
        backUser.setId(id);
        backUser.setUsername(bo.getUserName());
        backUser.setMobile(bo.getMobile());
        backUser.setSex(bo.getSex());
        backUser.setIsDeleted(0);
        backUser.setPassword(RSAUtil.encryptByPublicKey(bo.getPassword().getBytes(StandardCharsets.UTF_8), Constant.RSA_PUBLIC));
        backUser.setCreateBy("yhb");
        backUser.setCreateDate(new Date());
        int result = baseMapper.insert(backUser);
        return result == 0;
    }

    @Override
    public LoginUserInfoVo signIn(String username, String password) {
        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 构建请求体（请求参数）
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("username", username);
        body.add("password", password);
        body.setAll(BeanUtil.beanToMap(oAuth2ClientConfiguration));
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
        // 设置 Authorization
        restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(oAuth2ClientConfiguration.getClientId(),
                oAuth2ClientConfiguration.getSecret()));
        ResponseEntity<CommonResponse<Map<String, Object>>> responseEntity = null;

        try {
            // 发送请求
            responseEntity = restTemplate.exchange(UrlConstant.OAUTH_TOKEN_URL, HttpMethod.POST, entity, new ParameterizedTypeReference<CommonResponse<Map<String, Object>>>() {
            });
        } catch (Exception e) {
            throw new UserException(Constant.ERROR_CODE, Constant.LOGIN_FAIL);
        }

        if (responseEntity.getStatusCode() != HttpStatus.OK || responseEntity.getBody() == null) {
            throw new UserException(Constant.ERROR_CODE, Constant.LOGIN_FAIL);
        }

        CommonResponse<Map<String, Object>> result = responseEntity.getBody();
        if (!StringUtils.equals(result.getCode(), Constant.SUCCESS_CODE)) {
            throw new UserException(result.getCode(), result.getMessage());
        }

        // 这里的 Data 是一个 LinkedHashMap 转成了域对象 OAuthDinerInfo
        OAuthUserInfo userInfo = BeanUtil.fillBeanWithMap(Objects.requireNonNull(responseEntity.getBody()).getData(),
                new OAuthUserInfo(), false);

        LoginUserInfoVo vo = new LoginUserInfoVo();
        vo.setToken(userInfo.getAccessToken());
        vo.setUsername(userInfo.getUsername());
        return vo;
    }
}
